package com.xj.config;

import cn.hutool.core.collection.ConcurrentHashSet;
import com.xj.util.FreemakerUtil;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.init.ScriptUtils;

import javax.sql.DataSource;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author ricky
 * @date 2022/9/14
 */
@Slf4j
public abstract class BaseStandardShardingAlgorithm<T extends Comparable<?>> implements StandardShardingAlgorithm<T> {

    List<DataSource> dataSources;

    final Set<String> TABLES = new ConcurrentHashSet<>();

    private Properties props;

    abstract String getTableName();

    @Override
    public void init() {
        this.dataSources = Collections.singletonList(ShardingJdbcConfig.hikariDataSource);
        this.syncTable(getTableName());
    }

    /**
     * 读取所有表名称
     *
     * @author ricky
     * @date 2022/9/13
     */
    private void syncTable(String tableName) {
        String sql = "SELECT table_name FROM information_schema.tables WHERE table_name LIKE '" + tableName + "_%'";
        for (DataSource dataSource : this.dataSources) {
            try (PreparedStatement preparedStatement = dataSource.getConnection().prepareStatement(sql); ResultSet rs = preparedStatement.executeQuery()) {
                while (rs.next()) {
                    TABLES.add(rs.getString("table_name"));
                }
            } catch (SQLException e) {
                log.error("获取表名列表{}，错误:{}", tableName, e.getMessage(), e);
            }
        }
    }

    Lock lock = new ReentrantLock(true);

    void checkTable(String tableName) {
        lock.lock();
        try {
            if (!TABLES.contains(tableName)) {
                createTable(tableName);
            }
        } finally {
            lock.unlock();
        }
    }

    void createTable(String tableName) {
        try {
            log.info("创建表：{}", tableName);
            Template template = FreemakerUtil.getTemplate(getTableName() + ".ftl");
            Map<String, Object> context = new HashMap<>();
            context.put("tableName", tableName);
            StringWriter sw = new StringWriter();
            template.process(context, sw);
            Resource resource = new ByteArrayResource(sw.toString().getBytes(StandardCharsets.UTF_8));
            for (DataSource dataSource : this.dataSources) {
                try (Connection connection = dataSource.getConnection()) {
                    ScriptUtils.executeSqlScript(connection, resource);
                }
            }
            TABLES.add(tableName);
            // Thread.sleep(5000);
            log.info("创建表完成：{}", tableName);
        } catch (Exception e) {
            log.error("创建表({}) 异常:{}", tableName, e.getMessage(), e);
        }
    }


    @Override
    public Properties getProps() {
        return props;
    }

    @Override
    public void setProps(Properties props) {
        this.props = props;
    }
}
